package mc.support.task.mgr;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created with IntelliJ IDEA. <br/>
 * Author: Francis Yun    <br/>
 * Date: 2014-05-02  <br/>
 */
public class QueueGroup<T> {

    private final int queueCount;
    private final int queueCap;
    private List<QueueWrapper<T>> queues;

    public QueueGroup(int queueCount, int queueCap) {
        this.queueCount = queueCount;
        this.queueCap = queueCap;
        init();
    }

    private void init() {
        queues = new ArrayList<>( queueCount );
        for ( int i = 0; i < queueCount; i++ ) {
            BlockingQueue<T> bq = new ArrayBlockingQueue<>( queueCap );
            AtomicInteger stats = new AtomicInteger();
            QueueWrapper<T> qw = new QueueWrapper<>( bq, stats );
            queues.add( i , qw );
        }
    }

    private QueueWrapper<T> getMaximumQueue() {
        int maxSize = Integer.MIN_VALUE, index = 0, size;
        for ( int i = 0 ; i < queueCount; i++ ) {
            size = queues.get( i ).getStats().get();
            if ( size >= maxSize ) {
                maxSize = size;
                index = i;
            }
        }
        return queues.get( index );
    }

    private QueueWrapper<T> getMinimumQueue() {
        int minSize = Integer.MAX_VALUE, index = 0, size;
        for ( int i = 0 ; i < queueCount; i++ ) {
            size = queues.get( i ).getStats().get();
            if ( size <= minSize ) {
                minSize = size;
                index = i;
            }
        }
        return queues.get( index );
    }

    public T take() throws InterruptedException {
        QueueWrapper<T> qw = getMaximumQueue();
        T t = qw.getQueue().take();
        qw.getStats().decrementAndGet();
        return t;
    }

    public void put(T t) throws InterruptedException {
        QueueWrapper<T> qw = getMinimumQueue();
        qw.getQueue().put( t );
        qw.getStats().incrementAndGet();
    }

    public T poll() {
        QueueWrapper<T> qw = getMaximumQueue();
        T t = qw.getQueue().poll();
        if ( null != t ) {
            qw.getStats().decrementAndGet();
        }
        return t;
    }

    public boolean offer(T t) {
        QueueWrapper<T> qw = getMinimumQueue();
        boolean offered;
        if ( offered = qw.getQueue().offer( t ) ) {
            qw.getStats().incrementAndGet();
        }
        return offered;
    }

    public int totalSize() {
        int total = 0;
        for ( QueueWrapper<T> qw : queues ) {
            total += qw.getStats().get();
        }
        return total;
    }

    static class QueueWrapper<T> {

        private final BlockingQueue<T> queue;
        private final AtomicInteger stats;

        QueueWrapper(BlockingQueue<T> queue, AtomicInteger stats) {
            this.queue = queue;
            this.stats = stats;
        }

        public BlockingQueue<T> getQueue() {
            return queue;
        }

        public AtomicInteger getStats() {
            return stats;
        }

    }

}
